package org.zhadoop.stream.cql.semanticanalyzer.parser.context;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zhadoop.stream.api.streams.Column;
import org.zhadoop.stream.api.streams.Schema;
import org.zhadoop.stream.cql.DriverContext;
import org.zhadoop.stream.cql.exception.CQLException;
import org.zhadoop.stream.cql.exception.SemanticAnalyzerException;
import org.zhadoop.stream.cql.hooks.SemanticAnalyzeHook;
import org.zhadoop.stream.cql.semanticanalyzer.BaseAnalyzer;
import org.zhadoop.stream.cql.semanticanalyzer.SemanticAnalyzer;
import org.zhadoop.stream.cql.semanticanalyzer.analyzecontext.expressiondesc.ExpressionDescribe;
import org.zhadoop.stream.cql.semanticanalyzer.parsecontextreplacer.ParseContextReplacer;
import org.zhadoop.stream.cql.tasks.Task;
import org.zhadoop.streaming.exception.ErrorCode;

/**
 * 基础表达式解析内容
 * @author zwd
 *
 */
public abstract class BaseExpressionParseContext extends ParseContext{
	
	private static final Logger LOG = LoggerFactory.getLogger(BaseExpressionParseContext.class);

	private BaseExpressionParseContext leftExpression;
	
	private List<Schema> schemas;
	
	/**
	 * 遍历子表达式，如果匹配就替换
	 * @param replacer
	 */
	public abstract void walkChildAndReplace(ParseContextReplacer replacer);
	
	 /**
     * 创建表达式描述信息
     */
    protected abstract ExpressionDescribe createExpressionDesc()
        throws SemanticAnalyzerException;
	
    public ExpressionDescribe createExpressionDesc(List<Schema> allSchemas)
    	throws SemanticAnalyzerException{
    	schemas = allSchemas;
    	return createExpressionDesc();
    }

	public BaseExpressionParseContext getLeftExpression() {
		return leftExpression;
	}

	public void setLeftExpression(BaseExpressionParseContext leftExpression) {
		this.leftExpression = leftExpression;
	}

	public List<Schema> getSchemas() {
		return schemas;
	}

	public void setSchemas(List<Schema> schemas) {
		this.schemas = schemas;
	}
    
	/**
	 * 通过schema id找到其在Schema 数组中的索引
	 * @param schemaId
	 * @return
	 */
    public int getIndexInSchemas(String schemaId) throws SemanticAnalyzerException{
    	for(int i = 0; i < schemas.size() ; i++){
    		if(schemas.get(i).getId().equals(schemaId)){
    			return i;
    		}
    		
    		if(schemas.get(i).getName() != null && schemas.get(i).getName().equals(schemaId)){
    			return i;
    		}
    		
    		if(schemas.get(i).getStreamName() != null && schemas.get(i).getStreamName().equals(schemaId)){
    			return i;
    		}
    	}
    	
    	SemanticAnalyzerException exception = new SemanticAnalyzerException(ErrorCode.SEMANTICANALYZE_NO_STREAM, schemaId);
    	LOG.error(ErrorCode.SEMANTICANALYZE_NO_STREAM.getFullMessage(schemaId), exception);
    	throw exception;
    }
    
    /**
     * 通过属性名获取属性
     * 可能包含多个
     * @param attrName
     * @param schema
     * @return
     */
    public List<Column> getAttributeByName(String attrName,Schema schema){
    	return BaseAnalyzer.getAttributeByName(attrName, schema, schemas);
    }
    
    /**
     * 通过属性名获取属性
     * 可能包含多个
     * @param attrName
     * @return
     */
    public List<Column> getAttributeByName(String attrName){
    	return BaseAnalyzer.getAttributeByName(attrName, schemas);
    }
    
    /**
     * 通过属性名获取该属性所在的schemaid
     * 和getAttributeByName 是一一对应的
     * @param attrName
     * @return
     */
    protected List<String> getSchemaNameByAttrName(String attrName){
    	Set<String> res = new HashSet<>();
    	for(Schema schema : schemas){
    		if(getColumnByNameOrAlias(schema.getCols(), attrName).size() > 0){
    			res.add(schema.getId());
    		}
    	}
    	return new ArrayList<String>(res);
    }
    
    private List<Column> getColumnByNameOrAlias(List<Column> columns,String nameOrAlias){
    	List<Column> res = new ArrayList<>();
    	for(Column attr : columns){
    		if(!StringUtils.isEmpty(attr.getName()) && attr.getName().equalsIgnoreCase(nameOrAlias)){
    			res.add(attr);
    			continue;
    		}
    		if(!StringUtils.isEmpty(attr.getAlias()) && attr.getAlias().equalsIgnoreCase(nameOrAlias)){
    			res.add(attr);
    			continue;
    		}
    	}
    	return res;
    }
    
    /**
     * 获取所有流的所有属性
     * 适用于select * 
     * @return
     */
    protected List<Column> getAllAttributes(){
    	List<Column> attrs = new ArrayList<>();
    	for(Schema schema : schemas){
    		attrs.addAll(getAttributes(schema));
    	}
    	return attrs;
    }
    
    /**
     * 获取一个schema中所有的属性
     * @param schema
     * @return
     */
    protected List<Column> getAttributes(Schema schema){
    	return schema.getCols();
    }
    
    @Override
    public Task createTask(DriverContext driverContext, List<SemanticAnalyzeHook> analyzeHooks) throws CQLException {
    	return null;
    }
    
    @Override
    public SemanticAnalyzer createAnalyzer() throws SemanticAnalyzerException {
    	return null;
    }
	

}
